﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using CoreEx.Common.Extensions;
using CoreEx.DynamicInvoker;
using CoreEx.Wcf.Common.Implementation;
using LinFu.IoC.Configuration;
using LinFu.IoC.Interfaces;
using LinFu.IoC;
using System.ServiceModel.Channels;
using LinFu.Proxy.Interfaces;
using CoreEx.Wcf.Common;
using CoreEx.Common.Proxy;
namespace CoreEx.Wcf.Client.Implementation
{
    [Implements(typeof(IChannelProxyFactory))]
    public class ChannelProxyFactory : IChannelProxyFactory, IInitialize
    {
        private IServiceContractBuilder _serviceContractFactory;
        private IServiceContainer _serviceContainer;
        private IProxyFactory _proxyFactory;

        public object CreateChannelProxy(Type type)
        {
            //Create a service contract interface
            var serviceContractType = _serviceContractFactory.CreateServiceContract(type);

            //Get the binding
            var binding = _serviceContainer.GetService<Binding>(type.FullName);
            
            //Get the uri
            var uri = _serviceContainer.GetService<Uri>(type);

            var endpointAddress = new EndpointAddress(uri);

            //Create the generic channel factory

            Type channelFactoryType = typeof(ChannelFactory<>).MakeGenericType(new[] { serviceContractType });

            var channelFactory = Activator.CreateInstance(channelFactoryType, new object[] { binding, endpointAddress });

            //Get a reference to the service end point 
            var serviceEndPoint = (ServiceEndpoint)channelFactoryType.DynamicInvoke(channelFactory, "Endpoint");

            var endpointBehaviors = _serviceContainer.GetServices<IClientEndpointBehavior>();

            endpointBehaviors.ForEach(b => serviceEndPoint.Behaviors.Add(b));


            //Replace the default serializer
            foreach (var operationDescription in serviceEndPoint.Contract.Operations)
            {
                var defaultSerializerBehavior = operationDescription.Behaviors.Find<DataContractSerializerOperationBehavior>();
                var customSerializerBehavior =
                    _serviceContainer.GetService<IOperationBehavior>("CustomSerializerOperationBehavior", operationDescription);
                if (defaultSerializerBehavior != null)
                    operationDescription.Behaviors.Remove(defaultSerializerBehavior);
                operationDescription.Behaviors.Add(customSerializerBehavior);
            }
                        
           
            return _proxyFactory.CreateProxy(type, new DefaultServiceContractInterceptor(channelFactory), new Type[] {});
            
        }

        public void Initialize(IServiceContainer source)
        {
            _serviceContractFactory = source.GetService<IServiceContractBuilder>("ServiceContractBuilder");
            _proxyFactory = source.GetService<IProxyFactory>();
            _serviceContainer = source;
        }
    }
}
